#include "filereader.hpp"

std::vector <wxString> FileReader::getAstTbFX ()
{
	int namelength = 0;	//length of table 'specifier' entry (e.g. "$Impact Explosion:")
						//is set to 0 if nothing interesting on this line
	std::string parser;
	Filename *fn;
	std::vector <wxString> UsedFX;

	while (DaFile.good())
	{
		//Read next line
		std::getline(DaFile, parser);
		parser = Filename::trimString(parser);

		//Add future new asteroid-table-defined effects here, same way as for ships.tbl
		if (parser.compare(0, 18, "$Impact Explosion:") == 0)
			namelength = 18;
		else namelength = 0;

		if (namelength != 0)
		{
			fn = new Filename(parser.substr(namelength, parser.size()));
			UsedFX.push_back((*fn).getLower());
		}
	}
	return UsedFX;
}

std::vector <wxString> FileReader::getConfgFX ()
{
	int namelength = 0;	//length of table 'specifier' entry (e.g. "$Impact Explosion:")
						//is set to 0 if nothing interesting on this line
	std::string parser;
	Filename *fn;
	std::vector <wxString> UsedFX;

	while (DaFile.good())
	{
		//Read next line
		std::getline(DaFile, parser);
		parser = Filename::trimString(parser);

		//Add future new config-defined effects here, same way as for ships.tbl
		if (parser.compare(0, 9, "Filename:") == 0)
			namelength = 9;
		else namelength = 0;

		if (namelength != 0)
		{
			fn = new Filename(parser.substr(namelength, parser.size()));
			UsedFX.push_back((*fn).getLower());
		}
	}
	return UsedFX;
}

std::vector <wxString> FileReader::getFblTbFX ()
{
	int namelength = 0;	//length of table 'specifier' entry (e.g. "$Name:")
						//is set to 0 if nothing interesting on this line
	std::string parser;
	Filename *fn;
	std::vector <wxString> UsedFX;

	while (DaFile.good())
	{
		//Read next line
		std::getline(DaFile, parser);
		parser = Filename::trimString(parser);

		//Add future new fireball-table-defined effects here, same way as for ships.tbl
		if (parser.compare(0, 6, "$Name:") == 0)
			namelength = 6;
		else namelength = 0;

		if (namelength != 0)
		{
			fn = new Filename(parser.substr(namelength, parser.size()));
			UsedFX.push_back((*fn).getLower());
		}
	}
	return UsedFX;

}

std::vector <wxString> FileReader::getLgtTbFX ()
{
	int namelength = 0;	//length of table 'specifier' entry (e.g. "+b_texture:")
	//is set to 0 if nothing interesting on this line
	std::string parser;
	Filename *fn;
	std::vector <wxString> UsedFX;

	while (DaFile.good())
	{
		//Read next line
		std::getline(DaFile, parser);
		parser = Filename::trimString(parser);

		//Add future new lightning-table-defined effects here, same way as for ships.tbl
		if (parser.compare(0, 11, "+b_texture:") == 0)
			namelength = 11;
		else if (parser.compare(0, 8, "+b_glow:") == 0)
			namelength = 8;
		else namelength = 0;

		if (namelength != 0)
		{
			fn = new Filename(parser.substr(namelength, parser.size()));
			UsedFX.push_back((*fn).getLower());
		}
	}
	return UsedFX;
}

std::vector <wxString> FileReader::getMflTbFX ()
{
	int namelength = 0;	//length of table 'specifier' entry (e.g. "+blob_name:")
	//is set to 0 if nothing interesting on this line
	std::string parser;
	Filename *fn;
	std::vector <wxString> UsedFX;

	while (DaFile.good())
	{
		//Read next line
		std::getline(DaFile, parser);
		parser = Filename::trimString(parser);

		//Add future new mflash-table-defined effects here, same way as for ships.tbl
		if (parser.compare(0, 11, "+blob_name:") == 0)
			namelength = 11;
		else namelength = 0;

		if (namelength != 0)
		{
			fn = new Filename(parser.substr(namelength, parser.size()));
			UsedFX.push_back((*fn).getLower());
		}
	}
	return UsedFX;
}

std::vector <wxString> FileReader::getModelMaps ()
{
	int numtex;
	int numchar;
	char parser [FILENAME_MAX];		//C-style, ifstream::read just works like that
	std::vector<wxString> UsedMaps;

	//Models without maps, they exist. (MVPs subspacenode.pof)
	DaFile.seekg(8,std::ios_base::beg);
	DaFile.read(parser, 4);
	parser[4] = '\0';

	if (strcmp(parser, "TXTR") == 0)
	{
		//read number of textures
		DaFile.seekg(16,std::ios_base::beg);
		DaFile.read((char*) &numtex, 4);

		//iterate over textures
		DaFile.seekg(20,std::ios_base::beg);
		for (int j = 0; j < numtex; j++)
		{
			//get texture number of characters
			DaFile.read((char*) &numchar, 4);

			//read texture name
			DaFile.read(parser, numchar);
			parser[numchar] = '\0';

			//convert to lowercase
			for (int i = 0; i <= numchar; i++)
				parser[i] = static_cast<char>(tolower(parser[i]));

			UsedMaps.push_back(wxString(parser,wxConvUTF8));
		}
		return UsedMaps;
	}
	else
		return std::vector <wxString> ();
}

std::vector <wxString> FileReader::getModelFX ()
{
	int chunksz;
	int numfx;
	int numchar;
	int numpts;
	char parser [FILENAME_MAX];		//C-style, ifstream::read just works like that
	std::vector<wxString> UsedFX;

	//find glowpoint section by skipping over data chunks
	DaFile.seekg(12, std::ios_base::beg); //start here, at TXTR size
	do
	{
		DaFile.read((char*) &chunksz, 4); //read chunk size
		DaFile.seekg(chunksz, std::ios_base::cur); //skip over chunk
		DaFile.read (parser, 4); //read name of next chunk
		parser[4] = '\0';
	}
	while (strcmp(parser, "GLOW") != 0 && DaFile.good());

	if (DaFile.good())
	{ //found glowpoints
		//read number of glowpoints
		DaFile.seekg(4, std::ios_base::cur);
		DaFile.read((char*) &numfx, 4);

		DaFile.seekg(24, std::ios_base::cur);
		//iterate over glowpoint banks
		for (int j = 0; j < numfx; j++)
		{
			//get number of points in this bank
			DaFile.read((char*) &numpts, 4);

			//get glowpoint number of characters
			DaFile.read((char*) &numchar, 4);

			//crop $glow_texture= (14 chars)
			numchar -= 14;
			DaFile.seekg(14, std::ios_base::cur);

			//read effect name
			DaFile.read(parser, numchar);
			parser[numchar] = '\0';

			//convert to lowercase
			for (int i = 0; i <= numchar; i++)
				parser[i] = static_cast<char>(tolower(parser[i]));
			UsedFX.push_back(wxString(parser,wxConvUTF8));

			//move to next location
			//28 bytes per point; then 24 till no. points in next bank
			DaFile.seekg((28*numpts)+24, std::ios_base::cur);
		}
	}
	return UsedFX;
}

std::vector <wxString> FileReader::getNebTbFX ()
{
	int namelength = 0;	//length of table 'specifier' entry (e.g. "+Nebula:")
	//is set to 0 if nothing interesting on current line
	std::string parser;
	Filename *fn;
	std::vector <wxString> UsedFX;

	while (DaFile.good())
	{
		//Read next line
		std::getline(DaFile, parser);
		parser = Filename::trimString(parser);

		//Add future new asteroid-table-defined effects here, same way as for ships.tbl
		if (parser.compare(0, 8, "+Nebula:") == 0)
			namelength = 8;
		else if (parser.compare(0, 6, "+Poof:") == 0)
			namelength = 6;
		else namelength = 0;

		if (namelength != 0)
		{
			fn = new Filename(parser.substr(namelength, parser.size()));
			UsedFX.push_back((*fn).getLower());
		}
	}
	return UsedFX;

}

std::vector <wxString> FileReader::getSdfTbMaps ()
{
	int namelength = 0;	//length of table 'specifier' entry (e.g. "+Debris_Texture:")
	//is set to 0 if nothing interesting on this line
	std::string parser;
	Filename *fn;
	std::vector <wxString> UsedMaps;

	while (DaFile.good())
	{
		//Read next line
		std::getline(DaFile, parser);
		parser = Filename::trimString(parser);

		//Add future new sdf-table-defined maps here, same as for FX
		if (parser.compare(0, 16, "+Debris_Texture:") == 0)
			namelength = 16;
		else namelength = 0;

		if (namelength != 0)
		{
			fn = new Filename(parser.substr(namelength, parser.size()));
			UsedMaps.push_back((*fn).getLower());
		}
	}
	return UsedMaps;
}

std::vector <wxString> FileReader::getSdfTbFX ()
{
	int namelength = 0;	//length of table 'specifier' entry (e.g. "+Shield_Hit_ani:")
	//is set to 0 if nothing interesting on this line
	std::string parser;
	Filename *fn;
	std::vector <wxString> UsedFX;

	while (DaFile.good())
	{
		//Read next line
		std::getline(DaFile, parser);
		parser = Filename::trimString(parser);

		//Add future new sdf-table-defined effects here, should be pretty self-explanatory
		if (parser.compare(0, 16, "+Shield_Hit_ani:") == 0)
			namelength = 16;
		else if (parser.compare(0, 12, "+Pri_Normal:") == 0)
			namelength = 12;
		else if (parser.compare(0, 15, "+Pri_Afterburn:") == 0)
			namelength = 15;
		else if (parser.compare(0, 12, "+Sec_Normal:") == 0)
			namelength = 12;
		else if (parser.compare(0, 15, "+Sec_Afterburn:") == 0)
			namelength = 15;
		else if (parser.compare(0, 12, "+Ter_Normal:") == 0)
			namelength = 12;
		else if (parser.compare(0, 15, "+Ter_Afterburn:") == 0)
			namelength = 15;
		else if (parser.compare(0, 13, "+Dist_Normal:") == 0)
			namelength = 13;
		else if (parser.compare(0, 16, "+Dist_Afterburn:") == 0)
			namelength = 16;
		else if (parser.compare(0,  8, "+Normal:") == 0)
			namelength =  8;
		else if (parser.compare(0, 11, "+Afterburn:") == 0)
			namelength = 11;
		else namelength = 0;

		if (namelength != 0)
		{
			fn = new Filename(parser.substr(namelength, parser.size()));
			UsedFX.push_back((*fn).getLower());
		}
	}
	return UsedFX;
}

std::vector <wxString> FileReader::getShpTbMaps ()
{
	int namelength = 0;	//length of table 'specifier' entry (e.g. "+new:")
						//is set to 0 if nothing interesting on this line
	std::string parser;
	Filename *fn;
	std::vector <wxString> UsedMaps;

	while (DaFile.good())
	{
		//Read next line
		std::getline(DaFile, parser);
		parser = Filename::trimString(parser);

		//Add future new shp-table-defined maps here, see other methods for how it's done
		if (parser.compare(0, 5, "+new:") == 0)
			namelength = 5;
		else namelength = 0;

		if (namelength != 0)
		{
			fn = new Filename(parser.substr(namelength, parser.size()));
			UsedMaps.push_back((*fn).getLower());
		}
	}
	return UsedMaps;
}

std::vector <wxString> FileReader::getShpTbFX ()
{
	int namelength = 0;	//length of table 'specifier' entry (e.g. "$Warpout Animation:")
						//is set to 0 if nothing interesting on this line
	std::string parser;
	Filename *fn;
	std::vector <wxString> UsedFX;

	while (DaFile.good())
	{
		//Read next line
		std::getline(DaFile, parser);
		parser = Filename::trimString(parser);

		//Add future new ship-table-defined effects here, should be pretty self-explanatory
		if (parser.compare(0, 18, "$Warpin Animation:") == 0)
			namelength = 18;
		else if (parser.compare(0, 19, "$Warpout Animation:") == 0)
			namelength = 19;
		else if (parser.compare(0, 16, "$Shockwave Name:") == 0)
			namelength = 16;
		else if (parser.compare(0,  8, "+Bitmap:") == 0)
			namelength =  8;
		else if (parser.compare(0, 23, "$Thruster Normal Flame:") == 0)
			namelength = 23;
		else if (parser.compare(0, 28, "$Thruster Afterburner Flame:") == 0)
			namelength = 28;
		else if (parser.compare(0, 19, "$Thruster Bitmap 1:") == 0)
			namelength = 19;
		else if (parser.compare(0, 20, "$Thruster Bitmap 1a:") == 0)
			namelength = 20;
		else if (parser.compare(0, 19, "$Thruster Bitmap 2:") == 0)
			namelength = 19;
		else if (parser.compare(0, 20, "$Thruster Bitmap 2a:") == 0)
			namelength = 20;
		else if (parser.compare(0, 19, "$Thruster Bitmap 3:") == 0)
			namelength = 19;
		else if (parser.compare(0, 20, "$Thruster Bitmap 3a:") == 0)
			namelength = 20;
		else if (parser.compare(0, 28, "$Thruster Bitmap Distortion:") == 0)
			namelength = 28;
		else if (parser.compare(0, 30, "$Thruster Bitmap Distortion a:") == 0)
			namelength = 30;
		else if (parser.compare(0, 26, "$Thruster Particle Bitmap:") == 0)
			namelength = 26;
		else if (parser.compare(0, 29, "$Afterburner Particle Bitmap:") == 0)
			namelength = 29;
		else if (parser.compare(0,  9, "+Texture:") == 0)
			namelength =  9;
		else namelength = 0;

		if (namelength != 0)
		{
			fn = new Filename(parser.substr(namelength, parser.size()));
			UsedFX.push_back((*fn).getLower());
		}
	}
	return UsedFX;

}

std::vector <wxString> FileReader::getStrTbFX ()
{
	int namelength = 0;	//length of table 'specifier' entry (e.g. "$Bitmap:")
						//is set to 0 if nothing interesting on this line
	std::string parser;
	Filename *fn;
	std::vector <wxString> UsedFX;

	while (DaFile.good())
	{
		//Read next line
		std::getline(DaFile, parser);
		parser = Filename::trimString(parser);

		//Add future new str-table-defined effects here, should be pretty self-explanatory
		//If something is listed here, but not recognized by the program, check the number of chars
		if (parser.compare(0, 8, "$Bitmap:") == 0)
			namelength =  8;
		else if (parser.compare(0,  9, "$BitmapX:") == 0)
			namelength =  9;
		else if (parser.compare(0,  5, "$Sun:") == 0)
			namelength =  5;
		else if (parser.compare(0,  9, "$Sunglow:") == 0)
			namelength =  9;
		//following is a special one, currently supports up to 9 flares
		else if (parser.compare(0, 13, "$FlareTexture") == 0)
			namelength = 15;
		else if (parser.compare(0,  8, "$Debris:") == 0)
			namelength =  8;
		else if (parser.compare(0, 11, "$DebrisNeb:") == 0)
			namelength = 11;
		else namelength = 0;

		if (namelength != 0)
		{
			fn = new Filename(parser.substr(namelength, parser.size()));
			UsedFX.push_back((*fn).getLower());
		}
	}
	return UsedFX;
}

std::vector <wxString> FileReader::getWepTbFX ()
{
	int namelength = 0;	//length of table 'specifier' entry (e.g. "@Laser Bitmap:")
						//is set to 0 if nothing interesting on this line
	std::string parser;
	Filename *fn;
	std::vector <wxString> UsedFX;

	while (DaFile.good())
	{
		//Read next line
		std::getline(DaFile, parser);
		parser = Filename::trimString(parser);

		//Add future new weapons-table-defined effects here, should be pretty self-explanatory
		//If something is listed here, but not recognized by the program, check the number of chars
		if (parser.compare(0, 14, "@Laser Bitmap:") == 0)
			namelength = 14;
		else if (parser.compare(0, 12, "@Laser Glow:") == 0)
			namelength = 12;
		else if (parser.compare(0, 16, "$Shockwave Name:") == 0)
			namelength = 16;
		else if (parser.compare(0, 16, "$Shockwave Name:") == 0)
			namelength = 16;
		else if (parser.compare(0, 16, "+Shockwave Name:") == 0)
			namelength = 16;
		else if (parser.compare(0,  8, "+Bitmap:") == 0)
			namelength =  8;
		else if (parser.compare(0, 18, "$Impact Explosion:") == 0)
			namelength = 18;
		else if (parser.compare(0, 18, "$Impact Explosion:") == 0)
			namelength = 18;
		else if (parser.compare(0, 24, "$Dinky impact explosion:") == 0)
			namelength = 24;
		else if (parser.compare(0, 27, "$Piercing impact explosion:") == 0)
			namelength = 27;
		else if (parser.compare(0,  6, "+PAni:") == 0)
			namelength =  6;
		else if (parser.compare(0, 12, "+Muzzleglow:") == 0)
			namelength = 12;
		else if (parser.compare(0, 19, "+Beam Flash Effect:") == 0)
			namelength = 19;
		else if (parser.compare(0, 22, "+Beam Piercing Effect:") == 0)
			namelength = 22;
		else if (parser.compare(0,  9, "+Texture:") == 0)
			namelength =  9;
		//particle bitmap covered by trail bitmap above; decals dropped so unused
		else if (parser.compare(0, 23, "$Thruster Flame Effect:") == 0)
			namelength = 23;
		else if (parser.compare(0, 22, "$Thruster Glow Effect:") == 0)
			namelength = 22;
		else namelength = 0;

		if (namelength != 0)
		{
			fn = new Filename(parser.substr(namelength, parser.size()));
			UsedFX.push_back((*fn).getLower());
		}
	}
	return UsedFX;
}

void FileReader::resetFR()
{
	DaFileType = 0;
	DaFileName.clear();
	if (DaFile.is_open())
		DaFile.close();
}

FileReader::FileReader()
{
	resetFR();
}

bool FileReader::openFile(Filename name_in)
{
	resetFR(); // Fool-proofing
	wxString lowerName = name_in.getLower();

	if (lowerName.rfind(wxT(".pof")) == lowerName.size()-4)
	{
		DaFileType = MODEL;
	}
	else if (lowerName.rfind(wxT(".fs2")) == lowerName.size()-4)
	{
		DaFileType = MISSION;
	}
	else if (lowerName.rfind(wxT(".cfg")) == lowerName.size()-4)
	{
		DaFileType = CONFIG;
	}
	else if (lowerName == wxT("asteroid.tbl"))
	{
		DaFileType = ASTEROID_TBL;
	}
	else if (lowerName == wxT("fireball.tbl") || 
		lowerName.rfind(wxT("-fbl.tbm")) == lowerName.size()-8)
	{
		DaFileType = FIREBALL_TBL;
	}
	else if (lowerName == wxT("lightning.tbl"))
	{
		DaFileType = LIGHTNING_TBL;
	}
	else if (lowerName == wxT("mflash.tbl") || 
		lowerName.rfind(wxT("-mfl.tbm")) == lowerName.size()-8)
	{
		DaFileType = MFLASH_TBL;
	}
	else if (lowerName == wxT("nebula.tbl"))
	{
		DaFileType = NEBULA_TBL;
	}
	else if (lowerName == wxT("ships.tbl") || 
		lowerName.rfind(wxT("-shp.tbm")) == lowerName.size()-8)
	{
		DaFileType = SHIPS_TBL;
	}
	else if (lowerName == wxT("species_defs.tbl") || 
		lowerName.rfind(wxT("-sdf.tbm")) == lowerName.size()-8)
	{
		DaFileType = SDF_TBL;
	}
	else if (lowerName == wxT("stars.tbl") ||
		lowerName.rfind(wxT("-str.tbm")) == lowerName.size()-8)
	{
		DaFileType = STARS_TBL;
	}
	else if (lowerName == wxT("weapons.tbl") || 
		lowerName.rfind(wxT("-wep.tbm")) == lowerName.size()-8)
	{
		DaFileType = WEAPONS_TBL;
	}

	if (DaFileType == 0)
		return false;
	else
	{
		if (DaFileType == MODEL)
			DaFile.open(name_in.getCpp().c_str(), std::ifstream::in | std::ifstream::binary);
		else
			DaFile.open(name_in.getCpp().c_str(), std::ifstream::in);
		return DaFile.is_open();
	}
}

void FileReader::closeFile()
{
	DaFile.close();
	resetFR();
}

std::vector <wxString> FileReader::getMaps()
{
	//reset file before reading
	DaFile.clear();
	DaFile.seekg(0, std::ios_base::beg);

	if (DaFileType == MODEL)
		return getModelMaps();
	else if (DaFileType == MISSION)
		return getShpTbMaps(); //same syntax
	else if (DaFileType == ASTEROID_TBL)
		return std::vector <wxString> (); //no maps specified in asteroid.tbl
	else if (DaFileType == FIREBALL_TBL)
		return std::vector <wxString> (); //no maps specified in fireball.tbl
	else if (DaFileType == LIGHTNING_TBL)
		return std::vector <wxString> (); //no maps in lightning.tbl, only effects
	else if (DaFileType == MFLASH_TBL)
		return std::vector <wxString> (); //no maps here, only effects
	else if (DaFileType == NEBULA_TBL)
		return std::vector <wxString> (); //no maps in nebula.tbl, only effects
	else if (DaFileType == SDF_TBL)
		return getSdfTbMaps();
	else if (DaFileType == SHIPS_TBL)
		return getShpTbMaps();
	else if (DaFileType == STARS_TBL)
		return std::vector <wxString> (); //no maps in stars.tbl, only effects
	else if (DaFileType == WEAPONS_TBL)
		return std::vector <wxString> (); //no maps in weapons.tbl*/
	else if (DaFileType == CONFIG)
		return std::vector <wxString> (); //assuming no maps here
	else
	{
		return std::vector<wxString> ();
	}
}

std::vector <wxString> FileReader::getFX()
{
	//reset file before reading
	DaFile.clear();
	DaFile.seekg(0, std::ios_base::beg);

	if (DaFileType == MODEL)
		return getModelFX();
	else if (DaFileType == MISSION)
		return std::vector <wxString> (); //no effect files specified in mission
	else if (DaFileType == ASTEROID_TBL)
		return getAstTbFX();
	else if (DaFileType == FIREBALL_TBL)
		return getFblTbFX();
	else if (DaFileType == LIGHTNING_TBL)
		return getLgtTbFX();
	else if (DaFileType == MFLASH_TBL)
		return getMflTbFX();
	else if (DaFileType == NEBULA_TBL)
		return getNebTbFX();
	else if (DaFileType == SDF_TBL)
		return getSdfTbFX();
	else if (DaFileType == SHIPS_TBL)
		return getShpTbFX();
	else if (DaFileType == STARS_TBL)
		return getStrTbFX();
	else if (DaFileType == WEAPONS_TBL)
		return getWepTbFX();
	else if (DaFileType == CONFIG)
		return getConfgFX();
		
	else
	{
		return std::vector<wxString> ();
	}
}